package com.ccp.dev.workflow.bpmutil;

import com.ccp.dev.core.basic.db.datasource.DataSourceUtil;
import com.ccp.dev.core.basic.engine.GroovyScriptEngine;
import com.ccp.dev.core.basic.table.ColumnModel;
import com.ccp.dev.core.basic.table.SqlTypeConst;
import com.ccp.dev.core.jms.IMessageHandler;
import com.ccp.dev.core.util.AppUtil;
import com.ccp.dev.core.util.BeanUtils;
import com.ccp.dev.core.util.RequestContext;
import com.ccp.dev.core.util.StringUtil;
import com.ccp.dev.form.model.DialogField;
import com.ccp.dev.workflow.bpmconst.BpmConst;
import com.ccp.dev.workflow.bpminterface.ISkipCondition;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.ui.Model;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.sql.DataSource;
import java.util.*;

/**
 * ClassDescribe:流程工具类
 *
 * @author :jiayueqiao
 * Date: 2019-05-23
 * Since:1
 * To change this template use File | Settings | File Templates.
 */
public class ServiceUtil {

    /**
     * 获取跳过条件map集合。
     *
     * @return 跳过条件map集合
     */
    public static Map<String, ISkipCondition> getSkipConditionMap() {
        return (Map<String, ISkipCondition>) AppUtil.getBean("skipConditionMap");
    }

    /**
     * 获取消息处理器类型。
     *
     * @return 消息处理器集合
     */
    public static Map<String, IMessageHandler> getHandlerMap() {
        return (Map<String, IMessageHandler>) AppUtil.getBean("handlersMap");
    }


    /**
     * 根据别名获取JdbcTemplate对象。
     *
     * @param alias
     * @return
     * @throws Exception
     */
    public static JdbcTemplate getJdbcTemplate(String alias) throws Exception {
        JdbcTemplate jdbcTemplate = null;
        if (StringUtil.isEmpty(alias) || alias.equals(BpmConst.LOCAL_DATASOURCE)) {
            jdbcTemplate = (JdbcTemplate) AppUtil.getBean("jdbcTemplate");
        } else {
            DataSource dataSource = DataSourceUtil.getDataSourceByAlias(alias);
            jdbcTemplate = new JdbcTemplate(dataSource);
        }
        return jdbcTemplate;
    }

    /**
     * 判断任务执行人非空。
     *
     * @param assignee
     * @return
     */
    public static boolean isAssigneeNotEmpty(String assignee) {
        return !isAssigneeEmpty(assignee);
    }

    /**
     * 判断账号为空。
     *
     * @param assignee
     * @return
     */
    public static boolean isAssigneeEmpty(String assignee) {
        if (StringUtil.isEmpty(assignee) || BpmConst.EMPTY_USER.equals(assignee)) {
            return true;
        }
        return false;
    }

    /**
     * 取得用户连接。
     *
     * @param userId
     * @param fullName
     * @return
     */
    public static String getUserLink(String userId, String fullName) {
        return "<a onclick=\"authUserClick('" + userId + "')\" href=\"javascript:void(0);\" style=\"color: blue;margin-right: 5px;\">" + fullName + "</a>";
    }

    /**
     * 去到提示信息页。
     *
     * @param content
     * @return
     */
    public static String getTipInfo(Model model, String content) {
        model.addAttribute("content", content);
        return "workflow/task/tipInfo";
    }

    /**
     * 获取任务或实例页面处理路径
     *
     * @param id     流程运行id或者任务id
     * @param isTask 是否是任务
     * @return
     */
    public static String getUrl(String id, boolean isTask) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String contextPath = request.getContextPath();
        if (StringUtil.isEmpty(id)) {
            return "";
        }
        String url = "" + contextPath;
        if (isTask) {
            url += "/workflow/task/view/toStart?taskId=" + id;
        } else {
            url += "/workflow/processRun/view/info?runId=" + id;
        }
        return url;
    }

    public static String replaceTemplateTag(String template, String receiver, String sender, String subject, String url, String cause, boolean isSms) {
        if (StringUtil.isEmpty(template)) {
            return "";
        }
        if (cause == null) {
            cause = "";
        }
        template = template.replace("${收件人}", receiver)
                .replace("${发件人}", sender)
                .replace("${转办人}", sender)
                .replace("${代理人}", sender)
                .replace("${原因}", cause)
                .replace("${逾期级别}", cause)
                .replace("${事项意见}", cause);
        if (isSms || StringUtil.isEmpty(url)) {
            template = template.replace("${事项名称}", subject);
        } else {
            template = template.replace("${事项名称}", "<a href='" + url + "' target='_blank'>" + subject + "</a>");
        }

        // 替换特殊字符
        template = template.replaceAll("&nuot;", "\n");
        return template;
    }

    public static String replaceTitleTag(String template, String receiver, String sender, String subject, String cause) {
        if (StringUtil.isEmpty(template)) {
            return "";
        }
        template = template.replace("${收件人}", receiver)
                .replace("${发件人}", sender)
                .replace("${转办人}", sender)
                .replace("${代理人}", sender);
        if (StringUtil.isEmpty(cause)) {
            cause = "无";
        }
        template = template.replace("${原因}", cause)
                .replace("${逾期级别}", cause);

        template = template.replace("${事项名称}", subject);
        //替换特殊字符
        template = template.replaceAll("&nuot;", "\n");
        return template;
    }

    /**
     * 根据字符串获取不重复的ID列表
     *
     * @param uids
     * @return
     */
    public static List<String> queryNoSameIdsByStr(String uids) {
        //拆分
        String[] aryUid = uids.split("[,]");
        //去重
        Set<String> uidSet = new LinkedHashSet<String>();
        for (String orgId : aryUid) {
            uidSet.add(orgId);
        }
        //转换为list
        List<String> list = new ArrayList<String>();
        list.addAll(uidSet);
        return list;
    }

    /**
     * 获取列表的sql语句
     *
     * @param params 传入的条件列表。
     *               objectName 表名或视图名称。
     *               displayList显示字段列表
     *               conditionList条件字段列表。
     * @return String
     */
    public static String getSql(Map<String, Object> map, Map<String, Object> params, String dbType) {
        String objectName = (String) map.get("objectName");
        List<DialogField> retrunList = (List<DialogField>) map.get("returnList");
        List<DialogField> displayList = (List<DialogField>) map.get("displayList");
        List<DialogField> conditionList = (List<DialogField>) map.get("conditionList");
        List<DialogField> sortList = (List<DialogField>) map.get("sortList");
        String sql = "select ";
        if (BeanUtils.isEmpty(retrunList)) {
            sql = "select a.* from " + objectName + " a";
        } else {
            String returnStr = "";
            for (DialogField dialogField : retrunList) {
                returnStr += "," + dialogField.getFieldName();
            }
            returnStr = returnStr.replaceFirst(",", "");
            sql += returnStr + " from " + objectName;
        }
        String where = getWhere(conditionList, params, dbType);
        String orderBy = " order by ";
        if (BeanUtils.isEmpty(displayList)) {
            for (int i = 0; i < sortList.size(); i++) {
                DialogField df = sortList.get(i);
                if (i != 0) {
                    orderBy += ",";
                }
                orderBy += " " + df.getFieldName() + " " + df.getComment();
            }
            if (BeanUtils.isEmpty(sortList)) {
                return sql + where;
            }
            return sql + where + orderBy;
        }
        if (params.containsKey("sortField")) {
            orderBy += params.get("sortField");
        } else if (BeanUtils.isEmpty(sortList)) {
            orderBy += displayList.get(0).getFieldName();
        }
        //sortField有值或sortList为空
        if (!" order by ".equals(orderBy)) {
            if (params.containsKey("orderSeq")) {
                orderBy += " " + params.get("orderSeq");
            } else {
                orderBy += " ASC";
            }
            for (DialogField df : sortList) {
                // 添加一个判断  因为sqlserver不允许有重复的order by的字段。否则会报错
                if (!params.get("sortField").equals(df.getFieldName())) {
                    orderBy += ", " + df.getFieldName() + " " + df.getComment();
                }
            }
        } else {
            //sortField无值以及说sortList不为空
            for (DialogField df : sortList) {
                orderBy += df.getFieldName() + " " + df.getComment() + ",";
            }
        }
        sql = sql + where + orderBy;
        if (sql.trim().endsWith(",")) {
            sql = sql.substring(0, sql.length() - 1);
        }
        return sql;
    }

    /**
     * 取得where 条件。
     * <p>
     * 条件map。
     *
     * @param params 传入的参数
     * @return
     */
    public static String getWhere(List<DialogField> conditionList,
                                  Map<String, Object> params, String dbType) {
        StringBuffer sb = new StringBuffer();
        for (DialogField dialogField : conditionList) {
            getStringByDialogField(dialogField, params, sb,dbType);
        }
        if (sb.length() > 0) {
            return " where 1=1 " + sb.toString();
        }
        return "";
    }

    /**
     * 根据参数配置，上下文参数计算SQL语句。
     *
     * @param dialogField
     * @param params
     * @param sb
     */
    private static void getStringByDialogField(DialogField dialogField,
                                               Map<String, Object> params, StringBuffer sb, String dbType) {
        String field = dialogField.getFieldName();
        String condition = dialogField.getCondition();
        int conditionType = dialogField.getDefaultType();
        Object value = null;
        switch (conditionType) {
            case 1:
                if (params.containsKey(field)) {
                    value = params.get(field).toString();
                }
                break;
            case 2:
                value = dialogField.getDefaultValue();
                break;
            case 3:
                String script = dialogField.getDefaultValue();
                if (StringUtil.isNotEmpty(script)) {
                    GroovyScriptEngine groovyScriptEngine = (GroovyScriptEngine) AppUtil
                            .getBean(GroovyScriptEngine.class);
                    value = groovyScriptEngine.executeObject(script, null);
                }
                break;
            case 4:
                //向对话框传参数
                if (params.containsKey(field)) {
                    value = params.get(field).toString();
                }
                break;
            case 5:
                //java脚本
                String java = dialogField.getDefaultValue();
                if (StringUtil.isNotEmpty(java)) {
                    GroovyScriptEngine groovyScriptEngine = (GroovyScriptEngine) AppUtil
                            .getBean(GroovyScriptEngine.class);
                    Map<String, Object> paramsMap = new HashMap<>();
                    paramsMap.put("map", params);
                    value = groovyScriptEngine.executeObject(java, paramsMap);
                }
                break;

        }
        if (BeanUtils.isEmpty(value)) {
            //解决时间类型between条件时查不到数据
            if (!(params.containsKey("start" + field) || params.containsKey("end" + field))) {
                return;
            }
            value = "";
        }

        if (value.toString().indexOf("#,") != -1) {
            String temp = value.toString().replaceAll("#,", ",");
            sb.append(" and " + field + " in (" + temp + ")");
            return;
        }

        if (dialogField.getFieldType().equals(ColumnModel.COLUMNTYPE_VARCHAR)) {
            if ("=".equals(condition) || "<=".equals(condition) || ">=".equals(condition)) {
                sb.append(" and " + field + condition +" '" + value.toString() + "' ");
            } else if ("like".equals(condition)) {
                sb.append(" and " + field + " like '%" + value.toString()
                        + "%' ");
            } else if ("in".equals(condition)) {
				/*sb.append(" and " + field + " in (" + value.toString()
						+ ")");*/
                //在oracle中，如果in条件中用逗号分割的条件数大于10000个，直接写in条件报错
                //修改后语句例如：and (id in (0,1,2,3,4,5,6,7,8,9) or id in (10,11,12,13,14,15,16,17,18,19) or id in (20))
                sb.append("and (");
                String[] inArray = value.toString().split(",");
                int arrlen = inArray.length;
                StringBuilder tempSb = new StringBuilder();
                for (int i = 0; i < arrlen; i++) {
                    if (i % 1000 == 0) {
                        if (i != 0) {
                            tempSb.append(") or");
                        }
                        tempSb.append(field + " in (");
                    }
                    tempSb.append(inArray[i]);
                    if ((i + 1) % 1000 != 0 && i != arrlen - 1) {
                        tempSb.append(",");
                    }
                }
                tempSb.append(")");
                sb.append(tempSb.toString() + ")");

            } else if ("isNull".equals(condition)) {
                sb.append(" and " + field + " is null ");
            } else if ("isNotNull".equals(condition)) {
                sb.append(" and " + field + " is not null ");
            } else {
                sb.append(" and " + field + " like '%" + value.toString()
                        + "'");
            }
        } else if (dialogField.getFieldType().equals(
                ColumnModel.COLUMNTYPE_DATE)) {
              if ("=".equals(dialogField.getCondition())) {
                //oracle 数据库转换
                if (dbType.equals(SqlTypeConst.ORACLE) || dbType.equals(SqlTypeConst.POSTGRESQL)) {
                    sb.append(" and " + field + "=to_date('" + value + "','yyyy-mm-dd hh24:mi:ss') ");
                    if (!params.containsKey(field)) {
                        params.put(field, value);
                    }
                } else if (dbType.equals(SqlTypeConst.MYSQL)) {
                    sb.append(" and " + field + "=date_format('" + value + "','%Y-%m-%d %H-%i-%s') ");
                    if (!params.containsKey(field)) {
                        params.put(field, value);
                    }
                } else {
                    sb.append(" and " + field + "=:" + field + " ");
                    if (!params.containsKey(field)) {
                        params.put(field, value);
                    }
                }

            } else if (">=".equals(dialogField.getCondition())) {
                //oracle 数据库转换
                if (dbType.equals(SqlTypeConst.ORACLE) || dbType.equals(SqlTypeConst.POSTGRESQL)) {
                    if (conditionType == 1) {
                        if (params.containsKey(field)) {
                            sb.append(" and " + field + ">=to_date('" + value + "','yyyy-mm-dd hh24:mi:ss') ");
                        }
                    } else {
                        sb.append(" and " + field + ">=to_date('" + value + "','yyyy-mm-dd hh24:mi:ss') ");
                        params.put(field, value);
                    }
                } else if (dbType.equals(SqlTypeConst.MYSQL)) {
                    if (conditionType == 1) {
                        if (params.containsKey(field)) {
                            sb.append(" and " + field + ">=date_format('" + value + "','%Y-%m-%d %H-%i-%s') ");
                        }
                    } else {
                        sb.append(" and " + field + ">=date_format('" + value + "','%Y-%m-%d %H-%i-%s') ");
                        params.put(field, value);
                    }
                } else {
                    if (conditionType == 1) {
                        if (params.containsKey("start" + field.toLowerCase())) {
                            sb.append(" and " + field + ">=:start" + field.toLowerCase() + " ");
                        }
                    } else {
                        sb.append(" and " + field + ">=:start" + field + " ");
                        params.put("start" + field, value);
                    }
                }

            } else if ("<=".equals(dialogField.getCondition())) {
                //oracle 数据库转换
                if (dbType.equals(SqlTypeConst.ORACLE) || dbType.equals(SqlTypeConst.POSTGRESQL)) {
                    if (conditionType == 1) {
                        if (params.containsKey(field)) {
                            sb.append(" and " + field + "<=to_date('" + value + "','yyyy-mm-dd hh24:mi:ss') ");
                        }
                    } else {
                        sb.append(" and " + field + "<=to_date('" + value + "','yyyy-mm-dd hh24:mi:ss') ");
                        params.put(field, value);
                    }
                } else if (dbType.equals(SqlTypeConst.MYSQL)) {
                    if (conditionType == 1) {
                        if (params.containsKey(field)) {
                            sb.append(" and " + field + "<=date_format('" + value + "','%Y-%m-%d %H-%i-%s') ");
                        }
                    } else {
                        sb.append(" and " + field + "<=date_format('" + value + "','%Y-%m-%d %H-%i-%s') ");
                        params.put(field, value);
                    }
                } else {
                    if (conditionType == 1) {
                        if (params.containsKey("end" + field)) {
                            sb.append(" and " + field + "<=:end" + field + " ");
                        }
                    } else {
                        sb.append(" and " + field + "<=:end" + field + " ");
                        params.put("end" + field, value);
                    }
                }

            } else if ("isNull".equals(dialogField.getCondition())) {
                sb.append(" and " + field + " is null ");
            } else if ("isNotNull".equals(dialogField.getCondition())) {
                sb.append(" and " + field + " is not null ");
            }
            //添加时间类型between条件
            else if ("between".equals(dialogField.getCondition()) && conditionType == 1) {
                if (dbType.equals(SqlTypeConst.ORACLE) || dbType.equals(SqlTypeConst.POSTGRESQL)) {
                    String[] split = value.toString().split(",");
                    if (split.length == 2) {
                        if (params.containsKey(field)) {
                            sb.append(" and " + field + ">=to_date('" + split[0] + "','yyyy-mm-dd hh24:mi:ss') ");
                            sb.append(" and " + field + "<=to_date('" + split[1] + "','yyyy-mm-dd hh24:mi:ss') ");
                        }
                    }
                } else if (dbType.equals(SqlTypeConst.MYSQL)) {
                    String[] split = value.toString().split(",");
                    if (split.length == 2) {
                        if (params.containsKey(field)) {
                            sb.append(" and " + field + ">=date_format('" + split[0] + "','%Y-%m-%d %H-%i-%s') ");
                            sb.append(" and " + field + "<=date_format('" + split[1] + "','%Y-%m-%d %H-%i-%s') ");
                        }
                    }
                }else{
                    if (params.containsKey("start" + field)) {
                        sb.append(" and " + field + ">=:start" + field + " ");
                    }
                    if (params.containsKey("end" + field)) {
                        sb.append(" and " + field + "<=:end" + field + " ");
                    }
                }
            }
        } else {
            if (conditionType == 1) {
                if (params.containsKey(field)) {
                    sb.append(" and " + field + dialogField.getCondition()
                            + ":" + field + " ");
                }
            } else if (conditionType == 5) {
                if (value.toString().trim().startsWith("and")) {
                    sb.append(value.toString());
                } else {
                    sb.append(" and " + value.toString());
                }
            } else if (conditionType == 2) {
                //固定值不为varchar和date类型时
                sb.append(" and " + field + dialogField.getCondition() + value + " ");
            } else if ("isNull".equals(condition)) {
                sb.append(" and " + field + " is null ");
            } else if ("isNotNull".equals(condition)) {
                sb.append(" and " + field + " is not null ");
            } else {
                sb.append(" and " + field + dialogField.getCondition() + ":"
                        + field + " ");
                params.put(field, value);
            }
        }
    }
}
